
#include <iostream>
#include <numeric>
#include <string>
#include <vector>

class person_t;
void swap(person_t& a, person_t& b) noexcept;

class person_t {
    friend void swap(person_t& a, person_t& b) noexcept;

public:
    person_t()
    {
        std::cout << "constructor" << std::endl;
    }

    person_t(std::string n, std::string s)
        : name(std::move(n))
        , surname(std::move(s))
    {
        std::cout << "constructor with args" << std::endl;
    }

    person_t(const person_t& other)
        : name(other.name)
        , surname(other.surname)
    {
        std::cout << "copy constructor" << std::endl;
    }

    person_t(person_t&& other) noexcept
        : name(std::move(other.name))
        , surname(std::move(other.surname))
    {
        std::cout << "move constructor" << std::endl;
    }

    person_t& operator=(const person_t& other)
    {
        std::cout << "copy assignment operator" << std::endl;
        if (this != &other) {
            person_t temp(other);
            swap(*this, temp);
        }
        return *this;
    }

    person_t& operator=(person_t&& other) noexcept
    {
        std::cout << "move assignment operator" << std::endl;
        if (this != &other) {
            swap(*this, other);
        }
        return *this;
    }

    ~person_t()
    {
        std::cout << "destructor: " << name << " " << surname << std::endl;
    }

    person_t with_name(const std::string& name) const&
    {
        person_t result(*this);
        result.name = name;
        return result;
    }

    person_t with_name(const std::string& name) &&
    {
        person_t result(std::move(*this));
        result.name = name;
        return result;
    }

    person_t with_sur_name(const std::string& surname) const&
    {
        person_t result(*this);
        result.surname = surname;
        return result;
    }

    person_t with_sur_name(const std::string& surname) &&
    {
        person_t result(std::move(*this));
        result.surname = surname;
        return result;
    }

    std::string get_name() const
    {
        return name;
    }

    std::string get_surname() const
    {
        return surname;
    }

    void set_name(const std::string& name_)
    {
        name = name_;
    }

    void set_surname(const std::string& surname_)
    {
        surname = surname_;
    }

private:
    std::string name;
    std::string surname;
};

void swap(person_t& a, person_t& b) noexcept
{
    using std::swap;
    swap(a.name, b.name);
    swap(a.surname, b.surname);
}

person_t make(person_t p)
{
    p.set_name("make");
    return p;
}

// person_t make(person_t& p)
// {
//     p.set_name("make");
//     return p;
// }

// person_t make(person_t&& p)
// {
//     p.set_name("make");
//     return p;
// }

person_t make_rvo()
{
    person_t a;
    return a; // C++17之后叫做Mandatory Copy Elision
}

person_t make_nrvo()
{
    return person_t {}; // C++17之后叫做Mandatory Copy Elision
}

person_t make_aggregate()
{
    return person_t { "wyk", "" }; // C++17之后叫做Mandatory Copy Elision
}

void print_p(person_t p)
{
    std::cout << "person_t p " << p.get_name() << " " << p.get_surname() << std::endl;
}

// void print_p(person_t& p)
// {
//     std::cout << "person_t& p " << p.get_name() << " " << p.get_surname() << std::endl;
// }

// void print_p(person_t&& p)
// {
//     std::cout << "person_t&& p " << p.get_name() << " " << p.get_surname() << std::endl;
// }

int main()
{
    // std::cout << "--------make_rvo----------" << std::endl;
    // auto x = make_rvo();
    // std::cout << "---------make_nrvo---------" << std::endl;
    // auto y = make_nrvo();
    // std::cout << "---------make_aggregate---------" << std::endl;
    // auto z = make_aggregate();
    // std::cout << "---------person_t me = person_t {};---------" << std::endl;
    // person_t me = person_t {}; // Temporary Materialization Elision  不再有赋值
    // std::cout << "---------person_t he { person_t {} };---------" << std::endl;
    // person_t he { person_t {} }; // Guaranteed Copy Elision for prvalues

    person_t me { "Wayne", "Wei" };
    auto me1 = make(me);
    auto me2 = make({ "", "" });
    // print_p(me);
    // print_p(person_t {});
    // person_t other(me.with_name("Charlie"));
    // person_t he(person_t {});
    // person_t she(make());
    // me 左值
    // me.with_name("Charlie")右值

    std::vector<person_t> people { { "Wayne", "Wei" }, { "Tim", "Rose" } };
    std::cout << "-------------------------------" << std::endl;
    std::vector<int> vec(2, 1);
    auto result = std::accumulate(vec.begin(), vec.end(), person_t {},
        [](person_t acc, int) {
            return acc;
        });

#if __cplusplus == 199711L
    std::cout
        << "C++98/03" << std::endl;
#elif __cplusplus == 201103L
    std::cout
        << "C++11" << std::endl;
#elif __cplusplus == 201402L
    std::cout
        << "C++14" << std::endl;
#elif __cplusplus == 201703L
    std::cout
        << "C++17" << std::endl;
#elif __cplusplus == 202002L
    std::cout
        << "C++20" << std::endl;
#elif __cplusplus > 202002L
    std::cout
        << "C++23 or later" << std::endl;
#else
    std::cout
        << "Unknown C++ version: " << __cplusplus << std::endl;
#endif
    // auto a = make();
    // return 0;
}

// | 优化名称                                       | 标准版本    | 优化位置                | 是否强制                 | 简述                         |
// | ------------------------------------------ | ------- | ------------------- | -------------------- | -------------------------- |
// | **RVO** (Return Value Optimization)        | C++98 起 | `return T(...)`     | 否                    | 返回未命名临时对象时，编译器可就地构造。       |
// | **NRVO** (Named Return Value Optimization) | C++98 起 | `return local_var;` | 否（C++14），✅ 强制（C++17） | 返回局部具名变量时原地构造。             |
// | **Mandatory Copy Elision**                 | C++17 起 | 返回局部变量、构造临时值        | ✅ 强制                 | 不再调用 move/copy。            |
// | **Temporary Materialization Elision**      | C++17 起 | 临时对象初始化链            | ✅ 强制                 | prvalue 直接构造成目标对象，不经中间临时值。 |
// | **Aggregate Initialization Elision**       | C++20 起 | 聚合类型初始化             | ✅ 强制                 | 类似结构体直接初始化不再生成中间临时。        |
// | **Guaranteed Copy Elision for prvalues**   | C++17 起 | `T x = T(...);`     | ✅ 强制                 | prvalue 直接在 `x` 的存储上构造。    |
